﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Windows.Forms;
using PluginInterface;
using SasPlugIn.SASCli;
using SdmxMl.Common;
using SdmxMl.Excel;
using SdmxMl.Manager;
using SdmxMl.Structure;


namespace SasPlugIn
{
    /// <summary> User control for SAS PlugIn </summary>
    public partial class UcSas : UserControl, IPlugin
    {
        #region Internal members

        private CodeListType clt;
        private HierarchicalCodelistType hcl;
        private ConceptSchemeType cst;
        private HierarchyType hi;
        protected Dictionary<string, CodeListType> dico;
        private AnnotationInventory anInventory;
        private KeyFamilyType dsd;
        private CheckBox[] arrCheckboxLang;

        private DataLinkParameters dataLinkParam;

        #endregion

        #region Properties

        public IomProperties Properties { get; set; }

        #endregion

        #region Construction

        public UcSas()
        {
            InitializeComponent();

            //CheckBoxes for language availables
            arrCheckboxLang = new CheckBox[LangSupport.Count];
            int index = 0;
            foreach (string lg in LangSupport.SupportedLanguages)
            {
                arrCheckboxLang[index] = new CheckBox();
                panelTop.Controls.Add(arrCheckboxLang[index]);
                arrCheckboxLang[index].Size = new System.Drawing.Size(38, 17);
                arrCheckboxLang[index].Location = new System.Drawing.Point(286 + (index * 40), 10);
                arrCheckboxLang[index].Text = lg;
               // arrCheckboxLang[index].CheckAlign = System.Drawing.ContentAlignment.BottomCenter;
                if (lg == LangSupport.CurLang)
                    arrCheckboxLang[index].Checked = true;
                ++index;

            }

            // Initial state
            tableToolStripMenuItem.Enabled = false;
            dSDFormatToolStripMenuItem.Enabled = false;
            buttonExportFormat.Enabled = false;

            // fetch default serialized
            Properties = IomProperties.LoadDefault();

            // Fetch config if in app dir
            string ConfigBasePath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
            ConfigBasePath += "\\SasClient.cfg";
            if (System.IO.File.Exists(ConfigBasePath))
                Properties.XmlRead(ConfigBasePath);

            //Record event for selection change in main application tree
            ReferenceManager.TreeMgr.TreeSelect += new EventHandler(TreeMgr_TreeSelect);

            // Nomenclature format
            fillComboFormat();

            // Data link param initialisation
            dataLinkParam = new DataLinkParameters();
            // Fetch Link Param in app dir
            ConfigBasePath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
            ConfigBasePath += "\\SasDataLink.cfg";
            if (System.IO.File.Exists(ConfigBasePath))
            {
                dataLinkParam.XmlRead(ConfigBasePath);
                BindLinkToControls(dataLinkParam);
            }
        }

        #endregion

        #region Main Tree Select Event

        void TreeMgr_TreeSelect(object sender, EventArgs e)
        {
            try
            {
                // Fetch artefact selected (if meaningful)
                dsd = ReferenceManager.TreeSdmx.SelectedNode.Tag as KeyFamilyType;

                hcl = ReferenceManager.TreeSdmx.SelectedNode.Parent.Tag as HierarchicalCodelistType;
                hi = ReferenceManager.TreeSdmx.SelectedNode.Tag as HierarchyType;
                cst = ReferenceManager.TreeSdmx.SelectedNode.Tag as ConceptSchemeType;
                clt = ReferenceManager.TreeSdmx.SelectedNode.Tag as CodeListType;

                // Refresh menu state
                dSDFormatToolStripMenuItem.Enabled = dsd != null || clt != null;
                buttonExportFormat.Enabled = dSDFormatToolStripMenuItem.Enabled;

                if (cst != null)
                {
                    anInventory = new AnnotationInventory();
                    foreach (ConceptType c in cst.ConceptList)
                        anInventory.Inventory(c.AnnotationList, false);

                    dataGridViewAnnot.DataSource = anInventory.GenDataTableInfo();
                    UpdateTableName(cst.AgencyId, cst.Id);
                }
                else if (clt != null)
                {
                    anInventory = new AnnotationInventory();
                    foreach (CodeType c in clt.CodeList)
                        anInventory.Inventory(c.AnnotationList, false);

                    dataGridViewAnnot.DataSource = anInventory.GenDataTableInfo();
                    UpdateTableName(clt.AgencyId, clt.Id);

                }
                else if (hi != null)
                {
                    dico = GetRefDictionary(hi);

                    // Retrieve parent 
                    hcl = ReferenceManager.TreeSdmx.SelectedNode.Parent.Tag as HierarchicalCodelistType;
                    if (hcl != null)
                    {
                        anInventory = new AnnotationInventory();
                        foreach (KeyValuePair<string, CodeListType> kvp in dico)
                            foreach (CodeType c in kvp.Value.CodeList)
                                anInventory.Inventory(c.AnnotationList, false);

                        dataGridViewAnnot.DataSource = anInventory.GenDataTableInfo();
                        UpdateTableName(hcl.AgencyId, hcl.HierarchyList.Count > 1 ? hi.Id : hcl.Id);
                    }
                }
                else
                {
                    // Reset previous content for SAS table operation
                    DataTable tb = dataGridViewAnnot.DataSource as DataTable;
                    if (tb != null)
                    {
                        tb.Rows.Clear();
                        tb.AcceptChanges();
                    }
                    textBoxItemsName.Text = textBoxArtefactName.Text = string.Empty;
                    textBoxSasInfo.Text = string.Empty;
                }

                tableToolStripMenuItem.Enabled = textBoxItemsName.Text.Length > 0;

                // Nomenclature format
                fillComboFormat();

                
            }
            catch { }
       }

        private void UpdateTableName(string agency, string id)
        {
            string tableId = agency + "_" + id;
            textBoxArtefactName.Text = "AR_" + tableId;
            textBoxItemsName.Text = tableId;
        }

        private Dictionary<string, CodeListType> GetRefDictionary(HierarchyType hierarchy)
        {
            SmManager sm = ReferenceManager.GetSmContainerImage();
            Dictionary<string, CodeListType> dico = new Dictionary<string, CodeListType>();
            foreach (CodelistRefType crt in hierarchy.CodelistRefList)
            {
                CodeListType clType = null;
                Artefact a = sm.GetArtefact(SdmxArtefactType.CodeLists, crt);
                if (a != null)
                    clType = a as CodeListType;
                if (clType != null)
                    dico.Add(crt.Alias, clType);
            }

            return dico;
        }
        #endregion

        #region IPlugin Members

        /// <summary>Event is part of interface but not used </summary>
        public event PluginEvent PluginEventExposed
        {
            add { }
            remove { }
        }

        public void Init(System.Xml.XmlDocument xDoc, object obExtend)
        {
            // Nothing to do for this plug-in, configured for not called.
        }

        public UserControl VisualComponent()
        {
            return this;
        }

        public bool RequiresInit
        {
            get { return false; }
        }

        #endregion

        #region Config Events

        private void configureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                DlgSasClientConfig aDlg = new DlgSasClientConfig(Properties);
                aDlg.ShowDialog(this);

            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }
        #endregion

        #region Test Events

        /// <summary>Test SAS connection event </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void connectionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SasClient client = null;
            try
            {
                textBoxSasInfo.Text = string.Empty;
                using (new SdmxMl.Helper.CWaitCursor())
                {
                    client = new SasClient(Properties);
                    textBoxSasInfo.Text = client.CreateWorkspace();
                    textBoxSasInfo.Text += client.CreateTest("Libname metastat \"/app/home/bfs01/u4685/projet/Test/Phil/\";");

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                if (client != null)
                    client.Close();
            }

        }
        
        private void procInfoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SasClient client = null;
            try
            {
                textBoxSasInfo.Text = string.Empty;
                using (new SdmxMl.Helper.CWaitCursor())
                {
                    client = new SasClient(Properties);
                    textBoxSasInfo.Text = client.TestProcOptions();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                if (client != null)
                    client.Close();
            }
        }
        #endregion

        #region Export Event

        /// <summary> Export artefact metadata as table in SAS </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void exportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SasClient client = null;
            textBoxSasInfo.Text = string.Empty;
            try
            {
                using (new SdmxMl.Helper.CWaitCursor())
                {
                    dataGridViewAnnot.EndEdit();
                    DataTable tb = dataGridViewAnnot.DataSource as DataTable;
                    if (tb != null)
                        tb.AcceptChanges();

                    if (cst != null)
                    {
                        NomenExport nm = new NomenExport(Properties.TablePrefix);

                        client = new SasClient(Properties);

                        textBoxSasInfo.Text = client.CreateTest(GetLibPathCmd());

                        textBoxSasInfo.Text += client.CreateTest(nm.GenSpArtefact(cst, textBoxArtefactName.Text));
                        textBoxSasInfo.Focus();
                        textBoxSasInfo.Text += client.CreateTest(nm.GenSpConcept(cst, textBoxItemsName.Text, anInventory));
                        textBoxSasInfo.Focus();
                        textBoxSasInfo.SelectionStart = textBoxSasInfo.Text.Length;
                    }

                    else if (clt != null)
                    {
                        NomenExport nm = new NomenExport(Properties.TablePrefix);

                        client = new SasClient(Properties);

                        textBoxSasInfo.Text = client.CreateTest(GetLibPathCmd());

                        textBoxSasInfo.Text += client.CreateTest(nm.GenSpArtefact(clt, textBoxArtefactName.Text));
                        textBoxSasInfo.Focus();
                        textBoxSasInfo.Text += client.CreateTest(nm.GenSpCodelist(clt, textBoxItemsName.Text, anInventory));
                        textBoxSasInfo.Focus();
                        textBoxSasInfo.SelectionStart = textBoxSasInfo.Text.Length;
                    }
                    else if (hcl != null && hi != null)
                    {
                        NomenExport nm = new NomenExport(Properties.TablePrefix);

                        client = new SasClient(Properties);
                        textBoxSasInfo.Text = client.CreateTest(GetLibPathCmd());

                        textBoxSasInfo.Text += client.CreateTest(nm.GenSpArtefact(hcl, textBoxArtefactName.Text));
                        textBoxSasInfo.Focus();
                        textBoxSasInfo.Text += client.CreateTest(nm.GenSpHierarchy(hcl, hi, textBoxItemsName.Text, anInventory));
                        textBoxSasInfo.Focus();
                        textBoxSasInfo.SelectionStart = textBoxSasInfo.Text.Length;
                    }

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                if (client != null)
                    client.Close();
            }

        }

        private string GetLibPathCmd()
        {
            StringBuilder sb = new StringBuilder("Libname ");
            sb.Append(Properties.TablePrefix).Append(" \"");
            sb.Append(Properties.LibPath).Append("\";");
            return sb.ToString();
        }


        #endregion

        #region Grid Events

        /// <summary>
        /// Select / Unselect All in annotations list
        /// </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void dataGridViewAnnot_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.ColumnIndex == 0)
            {
                DataTable tb = dataGridViewAnnot.DataSource as DataTable;
                if (tb != null && tb.Rows.Count > 0)
                {
                    bool selectedFlag = ! (Convert.ToBoolean(tb.Rows[0][0]));
                    
                    foreach (DataRow r in tb.Rows)
                        r[0] = selectedFlag;

                    tb.AcceptChanges();
                }
            }
        }
        #endregion

        #region DSD Export Format

        private void dSDFormatToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SasClient client = null;
            textBoxSasInfo.Text = string.Empty;
            try
            {
                using (new SdmxMl.Helper.CWaitCursor())
                {
                    string s = string.Empty;
                    List<string> listLang = GetListFormatLang();

                    if (clt != null)
                    {
                        if (listLang.Count == 0)
                            throw new ApplicationException("No language checked for Format operation.");

                        FormatCodeAttributes fmt = new FormatCodeAttributes((CodeMapSel)comboBoxCodeMap.SelectedIndex,
                            (TextMapSel)comboBoxMapText.SelectedIndex, comboBoxCodeAnnotType.Text, comboBoxTextAnnotType.Text);
                        fmt.UseAbbreviation = checkBoxAbbrev.Checked;

                        CodeListFormat cf = new CodeListFormat(listLang, fmt);
                        StringBuilder sb = new StringBuilder();

                        sb.Append("PROC FORMAT LIBRARY=").Append(Properties.TablePrefix).Append(" ;").Append(Environment.NewLine);
                        cf.FillCodelistFormat(sb, clt, null, textBoxValueName.Text);
                        s = sb.ToString();
                    }
                    else if (dsd != null)
                    {
                        BindToLinkProperties();
                        if (dataLinkParam.IsFilled == false)
                            throw new ApplicationException("Parameters must be filled for link export");

                        FormatExport fmt = new FormatExport(ReferenceManager.GetSmContainerImage(), dsd, Properties, checkBoxAbbrev.Checked, listLang);
                        if (checkBoxExportFormat.Checked)
                        {
                            if (listLang.Count == 0)
                                throw new ApplicationException("No language checked for Format operation.");

                            s = fmt.GenFormat(dataLinkParam).ToString();
                        }
                        if (checkBoxExportLink.Checked)
                        {
                            s += fmt.GenLinkAndLabel(dataLinkParam, listLang.Count == 0 ? LangSupport.CurLang : listLang[0]);
                        }
                   }

                    if (s != string.Empty)
                    {
                        // Query file save
                        saveFileDialog.FileName = string.Empty;
                        saveFileDialog.Filter = "Text|*.txt|All files|*.*";
                        if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
                        {
                            using (System.IO.StreamWriter sw = new System.IO.StreamWriter(saveFileDialog.FileName, false, Encoding.Default))
                            {
                                sw.Write(s);
                                sw.Close();
                            }

                            textBoxSasInfo.Text = s;
                            System.Diagnostics.Process.Start(saveFileDialog.FileName);  
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                if (client != null)
                    client.Close();
            }
        }

        #endregion

        #region Combo Format

        private void fillComboFormat()
        {
            comboBoxCodeMap.Items.Clear();
            comboBoxMapText.Items.Clear();
            comboBoxCodeAnnotType.Items.Clear();
            comboBoxTextAnnotType.Items.Clear();

            // Basic choices
            comboBoxCodeMap.Items.Add("Code");

            comboBoxMapText.Items.Add("Name");
            comboBoxMapText.Items.Add("Description");

            // If annotations exist, extend choices
            if (anInventory != null && anInventory.Dico.Count > 0)
            {
                comboBoxCodeMap.Items.Add("Annotation Title");
                comboBoxCodeMap.Items.Add("Annotation Text");

                comboBoxMapText.Items.Add("Annotation Title");
                comboBoxMapText.Items.Add("Annotation Text");
                comboBoxMapText.Items.Add("Annotation Urn");

                foreach (AnnotationCount a in anInventory.Dico.Values)
                {
                    comboBoxCodeAnnotType.Items.Add(a.Annot.Type);
                    comboBoxTextAnnotType.Items.Add(a.Annot.Type);
                }

                //comboBoxCodeAnnotType.SelectedIndex = comboBoxTextAnnotType.SelectedIndex = 0;
            }
            comboBoxCodeMap.SelectedIndex = comboBoxMapText.SelectedIndex = 0;

            if (clt != null)
                textBoxValueName.Text = clt.Id.Replace("CL_", "");
            else
                textBoxValueName.Text = string.Empty;
        }


        #endregion

        #region Data Link Parameters

        #region Binding

        private void BindLinkToControls(DataLinkParameters p)
        {
            textBoxFormatLibPath.Text = p.FormatLibraryPath;
            textBoxDataEntryLibpath.Text = p.DataEntryLibraryPath;
            textBoxDataOutputLibPath.Text = p.DataOutputLibraryPath;
            textBoxDataSetEntryName.Text = p.DataSetEntryName;
            textBoxDataSetOutputName.Text = p.DataSetOutputName;
        }

        private void BindToLinkProperties()
        {
            dataLinkParam.FormatLibraryPath = textBoxFormatLibPath.Text;
            dataLinkParam.DataEntryLibraryPath = textBoxDataEntryLibpath.Text;
            dataLinkParam.DataOutputLibraryPath = textBoxDataOutputLibPath.Text;
            dataLinkParam.DataSetEntryName = textBoxDataSetEntryName.Text;
            dataLinkParam.DataSetOutputName = textBoxDataSetOutputName.Text;
        }

        #endregion

        #region Buttons Event

        private void buttonLoadMap_Click(object sender, EventArgs e)
        {
            try
            {
                openDialog.Filter = "SAS Data Link config files|*.cfg|All Files|*.*";
                if (openDialog.ShowDialog() != DialogResult.OK) return;
                {
                    dataLinkParam.XmlRead(openDialog.FileName);
                    BindLinkToControls(dataLinkParam);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to load config file: \n" + ex.Message);
            }


        }

        private void buttonSaveMap_Click(object sender, EventArgs e)
        {
            try
            {
                BindToLinkProperties();

                saveFileDialog.FileName = "SASDataLink.cfg";
                saveFileDialog.Filter = "SAS Data Link config files|*.cfg|All Files|*.*";
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                    dataLinkParam.XmlWrite(saveFileDialog.FileName);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to save config file: \n" + ex.Message);
            }
        }

        #endregion


        #endregion

        #region Languages list

        private List<string> GetListFormatLang()
        {
            List<string>langList = new List<string>();
            foreach (CheckBox cb in arrCheckboxLang)
            {
                if (cb.Checked)
                    langList.Add(cb.Text);
            }
            return langList;
        }
        #endregion
    }
}
